//
// Created by gj on 16-2-20.
//

#ifndef ALLUTILS_CTHREAD_H
#define ALLUTILS_CTHREAD_H

#include "ThreadSharePointer.h"

#include <pthread.h>

class ThreadAttr {
public:
    ThreadAttr() {
        pthread_attr_init(&p_attr);
    }

    virtual ~ThreadAttr() {
        int errCode = pthread_attr_destroy(&p_attr);
        if (errCode != 0) {
            LOG_W("--> Call pthread_attr_destroy error: errCode = %d", errCode);
        }
    }

    int detach() {
        return pthread_attr_setdetachstate(&p_attr, PTHREAD_CREATE_DETACHED);
    }

    bool isDetach() const;

private:
    LOG_CREATE_DEBUG

    pthread_attr_t p_attr;

    friend class CThread;
};

class CThread {
public:
    CThread(AsyncRunnable &_run) //
            : LOG_INIT_NAME("Thread") run(_run), result(NULL) {
        __create_pthread(NULL);
    }

    CThread(ThreadAttr &p_attr, AsyncRunnable &_run) //
            : LOG_INIT_NAME("Thread") run(_run), result(NULL) {
        __create_pthread(&p_attr);
    }

    virtual ~CThread();

    bool joinable() const {
        return !isRun;
    }

    int detach() {
        if (joinable()) {
            LOG_E_FUNC("Thread is join or detach");
        }
        isRun = false;
        return pthread_detach(p_id);
    }

    int join() {
        if (joinable()) {
            LOG_E_FUNC("Thread is join or detach");
        }
        isRun = false;
        return pthread_join(p_id, NULL);
    }

    pthread_t getPid() {
        return p_id;
    }

private:
    LOG_CREATE

    bool isRun;

    pthread_t p_id;

    AsyncRunnable run;

    void *result;

    void __create_pthread(ThreadAttr *attr);

    friend void *_thread_run(void *);
};

typedef ThreadSharePointer<CThread> Thread;

// --------------------------------------------- unit test --------------------------------------------------
#ifdef FLAG_UNIT_TESTING

void thread_unit_testing();

#endif

#endif //ALLUTILS_CTHREAD_H
